/*
 * LookingGlassDeclAst.cpp
 *
 *  Created on: 26 Nov 2010
 *      Author: kn308
 */

#include <MAlice/Parser/location.hh>
#include <MAlice/Ast/LookingGlassDeclAst.h>
#include <MAlice/Ast/LookingGlassCallAst.h>
#include <MAlice/Ast/FunctionDeclAst.h>
#include <MAlice/Ast/FunctionProtoAst.h>
#include <MAlice/Ast/FunctionParameterAst.h>

namespace MAlice
{

LookingGlassDeclAst::LookingGlassDeclAst(location loc, const string& name,
		PointerTypeAst* glassType, ListAst* body) :
	StatementAst(loc), mName(LookingGlassCallAst::MANGLING + name), mGlassType(
			glassType), mBody(body)
{
	MALICE_TRACE;

}

LookingGlassDeclAst::~LookingGlassDeclAst()
{
	MALICE_TRACE;
}

Value* LookingGlassDeclAst::generate()
{
	MALICE_TRACE;
	// looking glass has one parameter called 'it' with same type as the glass type

	Codegen* g = Codegen::get();
	// start function scope
	MALICE_AUTO_REVERSE(g);

	vector<const Type*> argTypes;
	argTypes.push_back(mGlassType->type());

	FunctionType* FT = FunctionType::get(Type::getVoidTy(g->getContext()), argTypes, false);
	Function* F = Function::Create(FT, Function::ExternalLinkage, mName, g->getModule());
	BasicBlock* BB = BasicBlock::Create(g->getContext(), "entry", F);
	Builder* builder = g->getBuilder();

	// create alloca for the function arguments
	builder->SetInsertPoint(BB);
	Function::arg_iterator arg = F->arg_begin();

	arg->setName("it");

	// create the argument alloca and push it on the variable table
	const Type* type = TypeAst(mLocation, mGlassType->getName()).type();
	g->pushVar("it", arg);

	g->setFunction(F);

	BasicBlock* bodyBB = BasicBlock::Create(g->getContext(), "body", F);
	builder->SetInsertPoint(bodyBB);
	mBody->generate();

	// return the default constructor for all functions
	builder->SetInsertPoint(&F->getBasicBlockList().back());
	builder->CreateRetVoid();

	return F;
}

}
